﻿
new function(jQun, Class, Enum, HTMLElementList, HTML, Event, Object, defineProperties, forEach){

this.PopupListStatus = (function(){
	return new Enum(
		["Show", "Hide"]
	);
}());

this.PopupList = (function(PopupListStatus, $window, statuschangedEvent, show, hide){
	function PopupList(selector, target){
		///	<summary>
		///	弹出层。
		///	</summary>
		///	<param name="selector" type="String, HTMLElement">元素选择器。</param>
		///	<param name="target" type="HTMLElement">触发弹出层的元素。</param>
		var popuplist = this;

		new HTMLElementList(
				target
			)
			.attach({
				click : function(e){
					popuplist.toggle();
				}
			});

		$window.attach({
			// 不用click的原因是：IE10，input监听keyup的enter键（执行this.blur()）会导致click的触发
			mouseup : function(e, $target){
				if(
					popuplist.status === PopupListStatus.Hide
				){
					return;
				}

				if(
					$target.isBtw([target, popuplist[0]])
				){
					return;
				}
				
				popuplist.hide();
			}
		});

		this.classList.add("popupList");
		this.hide();
	};
	PopupList = new Class(PopupList, "jQun.PopupList", HTMLElementList.prototype);

	PopupList.override({
		hide : function(){
			///	<summary>
			///	隐藏弹出层。
			///	</summary>
			this.status = PopupListStatus.Hide;

			hide.call(this);

			this.dispatch(
				statuschangedEvent,
				{ status : this.status }
			);

			return this;
		},
		show : function(){
			///	<summary>
			///	显示弹出层。
			///	</summary>
			this.status = PopupListStatus.Show;

			show.call(this);

			this.dispatch(
				statuschangedEvent,
				{ status : this.status }
			);

			return this;
		}
	});

	PopupList.props({
		status : PopupListStatus.Show
	});

	return PopupList.constructor;
}(
	this.PopupListStatus,
	// $window
	new HTMLElementList(window),
	// statuschangedEvent
	new Event("statuschanged"),
	HTMLElementList.prototype.show,
	HTMLElementList.prototype.hide
));

this.Options = (function(Array, html, undefined, selectoptionEvent, formatOpts){
	function Options(selector, _opts){
		///	<summary>
		///	下拉框选项类。
		///	</summary>
		///	<param name="selector" type="String, HTMLElement">元素选择器。</param>
		///	<param name="_opts" type="Object, Array">选项键值对或数组。</param>
		var options = this;

		this.attach({
			click : function(e, $target){
				if(
					!$target.isBtw(">li", this)
				){
					return;
				}

				options.select(
					$target.getData("key"),
					"click"
				);
				options.hide();
			}
		});

		if(
			!_opts
		){
			return;
		}

		this.append(_opts);
	};
	Options = new Class(Options, "jQun.Options", HTMLElementList.prototype);

	Options.props({
		append : function(opts){
			///	<summary>
			///	添加选项。
			///	</summary>
			///	<param name="opts" type="Object, Array, Enum">选项键值对或数组。</param>
			opts = formatOpts(opts);

			html.create(
					{ opts : opts }
				)
				.appendTo(
					this[0]
				);

			if(
				this.selectedKey === null
			){
				this.select(opts[0].key);
			}

			return this;
		},
		clear : function(_key){
			///	<summary>
			///	清空指定或所有选项。
			///	</summary>
			///	<param name="_key" type="String">需要删除项的关键字。</param>
			if(
				_key
			){
				this.query(
						'li[data-key="' + _key + '"]'
					)
					.remove();
			}
			else {
				this.innerHTML = "";
			}

			return this;
		},
		scrollTo : function(_key){
			///	<summary>
			///	滚动到指定关键字的项，如果未指定，则滚动到当前关键字项。
			///	</summary>
			///	<param name="key" type="String">指定的关键字。</param>
			var key = _key === undefined ? this.selectedKey : _key;

			if(
				key == null
			){
				return;
			}

			this.set(
				"scrollTop",
				this.query(
						'li[data-key="' + key + '"]'
					)
					.get(
						"offsetTop"
					)
			);

			return this;
		},
		searchText : function(text){
			///	<summary>
			///	从头搜索文本（不能从中间），返回第一个对应选项数据对象。
			///	</summary>
			///	<param name="text" type="String">需要搜索的文本字符串。</param>
			var result = { key : null, text : "" };

			this.query(
					">li"
				)
				.every(function(li){
					var liList = new HTMLElementList(li), txt = liList.innerHTML;

					if(
						txt.indexOf(text) === 0
					){
						result.key = liList.getData("key");
						result.text = txt;
						return false;
					}
				
					return true;	
				});

			return result;
		},
		select : function(key, _type){
			///	<summary>
			///	选择指定关键字的选项。
			///	</summary>
			///	<param name="key" type="String">指定的关键字。</param>
			///	<param name="_type" type="String">提供的类型标识，将作为事件属性之一。</param>
			var $new = this.query('li[data-key="' + key + '"]');

			if(
				$new.length === 0
			){
				return $new;
			}
			
			var text = $new.innerHTML;

			this.selectedKey = key;
			this.selectedText = text;

			this.query('li[data-selected]').removeData("selected");

			$new.setData(
				"selected"
			).dispatch(
				selectoptionEvent,
				{
					selectedKey : key,
					text : text,
					selectType : typeof _type === "undefined" ? null : _type
				}
			);
			
			return $new;
		},
		selectedKey : null,
		selectedText : ""
	});

	return Options.constructor;
}(
	Array,
	// html
	new HTML([
		'@for(opts ->> option){',
			'<li data-key="{option.key}" title="{?~option.title || option.text}">{option.text}</li>',
		'}'
	].join("")),
	undefined,
	// selectoptionEvent
	new Event("selectoption"),
	// formatOpts
	function(opts){
		if(
			opts instanceof Array
		){
			return opts.map(function(data, i){
				if(
					data instanceof Object
				){
					return data;
				}

				return {
					text : data,
					key : i,
					title : data
				};
			});
		}

		var result = [];

		if(
			opts instanceof Enum
		){
			opts.forEach(
				function(key, text){
					result.push({
						text : text,
						key : key,
						title : text
					});
				}
			);
		}

		return result;
	}
));

this.DropDownList = (function(PopupList, Options, PopupListStatus, html, $window){
	function DropDownList(_opts){
		///	<summary>
		///	下拉框控件类。
		///	</summary>
		///	<param name="_opts" type="Array, Object">下拉框选项列表。</param>
		var options, dropDownList = this;

		this.combine(
				html.create()
			)
			.assign({
				options : new Options(
					this.query(">ol")[0],
					_opts
				)
			})
			.attach({
				selectoption : function(e){
					dropDownList.query("input").value = e.text;
				}
			});

		options = this.options;

		new PopupList(
				options[0],
				this.query(">p>button")[0]
			)
			.attach({
				statuschanged : function(e){
					if(
						e.status === PopupListStatus.Show
					){
						options.scrollTo();
					}
				}
			});
	};
	DropDownList = new Class(DropDownList, "jQun.DropDownList", HTMLElementList.prototype);

	return DropDownList.constructor;
}(
	this.PopupList,
	this.Options,
	this.PopupListStatus,
	// html
	new HTML([
		'<div class="dropDownList" data-bgcolor="black" data-radius="small">',
			'<p data-color="white">',
				'<input type="text" data-radius="small" readonly />',
				'<button data-border="black" data-bgcolor="deep-gray"></button>',
			'</p>',
			'<ol hidden data-status="0" data-radius="small"></ol>',
		'</div>'
	].join(""))
));

this.WriteableList = (function(DropDownList, changeEvent){
	function WriteableList(){
		///	<summary>
		///	可写入的下拉框。
		///	</summary>
		var writeableList = this, inputList = this.query("input");

		inputList.removeAttribute("readonly");
		
		this.attach({
			selectoption : function(e){
				changeEvent.trigger(inputList[0]);
			}
		});
	};
	WriteableList = new Class(WriteableList, "jQun.WriteableList", DropDownList.prototype);

	return WriteableList.constructor;
}(
	this.DropDownList,
	// changeEvent
	new Event("change")
));

this.SearchableList = (function(WriteableList, SearchableInput){
	function SearchableList(){
		///	<summary>
		///	可搜索的下拉列表。
		///	</summary>
		var lastValue = "", options = this.options;

		this.query(
			"input"
		).attach({
			focus : function(){
				lastValue = this.value;
			},
			keyup : function(e){
				var text = this.value, length = text.length;

				if(
					length === 0
				){
					return;
				}

				switch(e.keyCode){
					case 8 :
						return;

					case 46 :
						return;

					case 20 :
						return;

					case 39 :
						break;

					case 13 :
						this.blur();
						return;

					default :
						if(
							lastValue === text
						){
							return;
						}
				}
				
				var result = options.searchText(text);
				
				if(
					result.key === null
				){
					return;
				}

				this.value = result.text;
				this.selectionStart = length;
				this.selectionEnd = this.value.length;
			},
			blur : function(){
				var key = null, text = this.value, selectedText = options.selectedText;

				if(
					text === selectedText
				){
					return;
				}

				var selectedKey = options.selectedKey;

				if(
					text.length > 0
				){
					key = options.searchText(text).key;
				}

				if(
					key === null
				){
					key = selectedKey;
				}

				if(
					key === selectedKey
				){
					this.value = selectedText;
				}

				options.select(key, "blur");
			}
		});
	};
	SearchableList = new Class(SearchableList, "jQun.SearchableList", WriteableList.prototype);

	return SearchableList.constructor;
}(
	this.WriteableList,
	this.SearchableInput
));

defineProperties(jQun, this);
}(
	jQun,
	jQun.Class,
	jQun.Enum,
	jQun.HTMLElementList,
	jQun.HTML,
	jQun.Event,
	Object,
	jQun.defineProperties,
	jQun.forEach
);